package edu.sdwu.liqing.qasystem.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import edu.sdwu.liqing.qasystem.dto.QADto;
import edu.sdwu.liqing.qasystem.dto.QaQuestionDto;
import edu.sdwu.liqing.qasystem.entity.*;
import edu.sdwu.liqing.qasystem.mapper.EsAnswerMapper;
import edu.sdwu.liqing.qasystem.mapper.EsQuestionMapper;
import edu.sdwu.liqing.qasystem.mapper.QaQuestionMapper;
import edu.sdwu.liqing.qasystem.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.sdwu.liqing.qasystem.util.OperateUtil;
import edu.sdwu.liqing.qasystem.util.RequestUtil;
import edu.sdwu.liqing.qasystem.vo.QaQuestionVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>
 * 问题表  服务实现类
 * </p>
 *
 * @author liqing@sdwu.edu
 * @since 2020-03-22
 */
@Service
@Slf4j
public class QaQuestionServiceImpl extends ServiceImpl<QaQuestionMapper, QaQuestion> implements IQaQuestionService {

    @Autowired
    OperateUtil operateUtil;

    @Autowired
    RequestUtil requestUtil;

    @Autowired
    IQaUserService userService;

    @Autowired
    IQaModuleService moduleService;

    @Autowired
    IQaAnswerService answerService;

    @Autowired
    IQaRoleModuleService roleModuleService;

    @Autowired
    EsQuestionMapper esQuestionMapper;

    @Autowired
    EsAnswerMapper esAnswerMapper;

    @Override
    public boolean save(QaQuestion question) {
        if (StringUtils.isAnyBlank(question.getTitle(), question.getContent(), question.getModuleId())) {
            throw new RuntimeException("参数校验不合法");
        }
        //todo 增加權限過濾 是否有新增權限
        if (!operateUtil.canAddQuestion(question.getModuleId())) {
            return false;
        }
        question.setAnswerNum(0);
        question.setSolved(false);
        boolean flag =  super.save(question);
        if (flag) {
            EsQuestionEntity entity = new EsQuestionEntity();
            entity.setId(question.getId());
            entity.setContent(filterChinese(question.getContent()));
            log.info("过滤中文后内容：{}", entity.getContent());
            entity.setTitle(question.getTitle());
            esQuestionMapper.save(entity);
        }
        return flag;
    }

    @Override
    public boolean update(QaQuestion qaQuestion) {
        //todo 增加權限過濾 是否有修改權限
        QaQuestion question = super.getById(qaQuestion.getId());
        if (Objects.isNull(question)) {
            return false;
        }
        if (!operateUtil.canOperate(question)) {
            return false;
        }
        return super.updateById(qaQuestion);
    }

    @Override
    public boolean delete(String id) {
        if (StringUtils.isBlank(id)) {
            return false;
        }
        //todo 增加權限過濾 是否有刪除權限
        QaQuestion question = super.getById(id);
        if (Objects.isNull(question)) {
            return false;
        }
        if (!operateUtil.canOperate(question)) {
            return false;
        }
        return super.removeById(id);
    }

    @Override
    public Page<QaQuestion> page(QaQuestionVo vo) {
        QaUser currentUser = requestUtil.getCurrentUser();
        //这里要做一下模块过滤。过滤该角色能看到的模块
        List<String> moduleIdList = roleModuleService.getModuleIdListByRoleId(requestUtil.getCurrentUser().getRoleId());
        if (CollectionUtils.isEmpty(moduleIdList)) {
            return vo.getPage();
        }
        QueryWrapper<QaQuestion> qw = Wrappers.query();
        qw.select("id", "create_by as createdBy", "create_time as createdTime", "title", "answer_num", "solved", "module_id");
        qw.in("module_id", moduleIdList);
        //todo es全文檢索
        qw.like(StringUtils.isNotBlank(vo.getKeyword()), "title", vo.getKeyword());
        qw.eq(StringUtils.isNotBlank(vo.getModuleId()), "module_id", vo.getModuleId());
        Page<QaQuestion> page = super.page(vo.getPage(), qw);
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            page.getRecords().parallelStream().forEach(i-> {
                QaUser user = userService.getById(i.getCreatedBy());
                if (Objects.nonNull(user)) {
                    i.setCreatedName(user.getRealName());
                }
                QaModule module = moduleService.getById(i.getModuleId());
                if (Objects.nonNull(module)) {
                    i.setModuleName(module.getModuleName());
                }
                i.setCanOperate(StringUtils.containsIgnoreCase("ADMIN", currentUser.getRoleName()) || StringUtils.equals(currentUser.getId(), i.getCreatedBy()));
            });
        }
        return page;
    }

    @Override
    public QaQuestionDto get(String id) {
        if (StringUtils.isBlank(id)) {
            return new QaQuestionDto();
        }
        QaQuestion question = super.getById(id);
        if (Objects.isNull(question) || !operateUtil.canAddQuestion(question.getModuleId())) {
            return new QaQuestionDto();
        }
        QaQuestionDto questionDto = new QaQuestionDto();
        //复制属性
        BeanUtils.copyProperties(question, questionDto);
        //设置好回答列表
        questionDto.setAnswerList(answerService.listByQuestionId(questionDto.getId()));
        //设置属性
        QaUser user = userService.getById(questionDto.getCreatedBy());
        if (Objects.nonNull(user)) {
            questionDto.setCreatedName(user.getRealName());
        }
        QaModule module = moduleService.getById(questionDto.getModuleId());
        if (Objects.nonNull(module)) {
            questionDto.setModuleName(module.getModuleName());
        }
        return questionDto;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean saveQuestionAndAnswer(QADto dto) {
        if (Objects.isNull(dto) || Objects.isNull(dto.getAnswer()) || Objects.isNull(dto.getQuestion())) {
            return false;
        }
        boolean flag = this.save(dto.getQuestion());
        if (flag) {
            boolean flag_answer = answerService.save(dto.getAnswer());
            if (!flag_answer) {
                throw new RuntimeException("保存出错");
            }
        }
        return flag;
    }

    @Override
    public QaQuestion getByModuleId(String moduleId) {
        if (StringUtils.isBlank(moduleId)) {
            return null;
        }
        QueryWrapper<QaQuestion> qw = Wrappers.query();
        qw.eq("module_id", moduleId);
        qw.last("limit 1");
        return super.getOne(qw);
    }

    public List<QaQuestion> list(String keyword) {
        if (StringUtils.isBlank(keyword)) {
            return Lists.newArrayListWithExpectedSize(0);
        }
        //取出问题的检索列表
        List<String> questionEntityList = new ArrayList<>();
        List<String> answerEntityList = new ArrayList<>();
        Iterator<EsQuestionEntity> esQuestionIterator = esQuestionMapper.search(QueryBuilders.multiMatchQuery(keyword,
                "title",
                "content"
                )).iterator();
        while(esQuestionIterator.hasNext()) {
            questionEntityList.add(esQuestionIterator.next().getId());
        }

        Iterator<EsAnswerEntity> esAnswerIterator = esAnswerMapper.search(QueryBuilders.multiMatchQuery(keyword,
                "content"
        )).iterator();
        while(esAnswerIterator.hasNext()) {
            answerEntityList.add(esAnswerIterator.next().getQuestionId());
        }
        //取并集
        questionEntityList.removeAll(answerEntityList);
        questionEntityList.addAll(answerEntityList);
        log.info("{}", questionEntityList );
        if (CollectionUtils.isEmpty(questionEntityList)) {
            return Lists.newArrayListWithExpectedSize(0);
        }

        QaUser currentUser = requestUtil.getCurrentUser();
        //这里要做一下模块过滤。过滤该角色能看到的模块
        List<String> moduleIdList = roleModuleService.getModuleIdListByRoleId(requestUtil.getCurrentUser().getRoleId());
        if (CollectionUtils.isEmpty(moduleIdList)) {
            return Lists.newArrayListWithExpectedSize(0);
        }
        QueryWrapper<QaQuestion> qw = Wrappers.query();
        qw.select("id", "create_by as createdBy", "create_time as createdTime", "title", "answer_num", "solved", "module_id");
        qw.in("module_id", moduleIdList);
        qw.in("id", questionEntityList);
        return super.list(qw);
    }

    @Override
    public Page<QaQuestion> currentPage(QaQuestionVo vo) {
        QaUser currentUser = requestUtil.getCurrentUser();
        //这里要做一下模块过滤。过滤该角色能看到的模块
        List<String> moduleIdList = roleModuleService.getModuleIdListByRoleId(requestUtil.getCurrentUser().getRoleId());
        if (CollectionUtils.isEmpty(moduleIdList)) {
            return vo.getPage();
        }
        QueryWrapper<QaQuestion> qw = Wrappers.query();
        qw.select("id", "create_by as createdBy", "create_time as createdTime", "title", "answer_num", "solved", "module_id");
        qw.in("module_id", moduleIdList);
        qw.eq("create_by", currentUser.getId());
        //todo es全文檢索
        qw.like(StringUtils.isNotBlank(vo.getKeyword()), "title", vo.getKeyword());
        qw.eq(StringUtils.isNotBlank(vo.getModuleId()), "module_id", vo.getModuleId());
        Page<QaQuestion> page = super.page(vo.getPage(), qw);
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            page.getRecords().parallelStream().forEach(i-> {
                QaUser user = userService.getById(i.getCreatedBy());
                if (Objects.nonNull(user)) {
                    i.setCreatedName(user.getRealName());
                }
                QaModule module = moduleService.getById(i.getModuleId());
                if (Objects.nonNull(module)) {
                    i.setModuleName(module.getModuleName());
                }
                i.setCanOperate(StringUtils.containsIgnoreCase("ADMIN", currentUser.getRoleName()) || StringUtils.equals(currentUser.getId(), i.getCreatedBy()));
            });
        }
        return page;
    }

    @Override
    public boolean solved(String key) {
        QaQuestion question = super.getById(key);
        if (Objects.isNull(question)) {
            return false;
        }
        if (!StringUtils.equals(question.getCreatedBy(), requestUtil.getCurrentUser().getId())) {
            return false;
        }
        if (question.getAnswerNum() == 0) {
            return false;
        }
        question.setSolved(true);
        return super.updateById(question);
    }

    private static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);
        if (m.find()) {
            return true;
        }
        return false;
    }

    private static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
            return true;
        }
        return false;
    }

    public static String filterChinese(String str) {
        String result = str;
        boolean Containflag = isContainChinese(str);
        if (Containflag) {
            // 拼接字符
            StringBuffer strBu = new StringBuffer();
            // 单个字符判断
            boolean singleflag = false;
            char[] strArray = str.toCharArray();
            for (int i = 0; i < strArray.length; i++) {
                singleflag = isChinese(strArray[i]);
                if (singleflag) {
                    strBu.append(strArray[i]);
                }
            }
            result = strBu.toString();
        }
        return result;
    }

}
